﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Data.SqlClient;
using Microsoft.Reporting.WinForms;
using SSRSViewer.Core;

namespace SSRSViewer.Win
{
	public partial class ReportViewer : UserControl
	{
		static ParameterEditorLibrary editors;
		public static ParameterEditorLibrary Editors
		{
			get
			{
				if (editors == null)
				{
					editors = new ParameterEditorLibrary();
					editors.Add(typeof(IMultipleValidValuesUserControl), typeof(MultipleValidValuesUserControl));
					editors.Add(typeof(IBooleanParameterUserControl), typeof(BooleanParameterUserControl));
					editors.Add(typeof(IDateParameterUserControl), typeof(DateParameterUserControl));
					editors.Add(typeof(IFloatParameterUserControl), typeof(FloatParameterUserControl));
					editors.Add(typeof(IIntegerParameterUserControl), typeof(IntegerParameterUserControl));
					editors.Add(typeof(ISingleValidValueUserControl), typeof(SingleValidValueUserControl));
					editors.Add(typeof(IStringParameterUserControl), typeof(StringParameterUserControl));
				}

				return editors;
			}
		}


		log4net.ILog log = log4net.LogManager.GetLogger(typeof(ReportViewer));
		SqlConnection DatabaseConnection { get; set; }
		RdlParser ReportParser { get; set; }
		Stream Report { get; set; }

		public event EventHandler ReportPrinted;

		public ReportViewer()
		{
			InitializeComponent();
			btnRunReport.Click += new EventHandler(btnRunReport_Click);
			viewer.Print += new ReportPrintEventHandler(viewer_Print);
			viewer.RenderingComplete += new RenderingCompleteEventHandler(viewer_RenderingComplete);
		}

		void viewer_Print(object sender, ReportPrintEventArgs e)
		{
			OnPrint();
		}

		void viewer_RenderingComplete(object sender, RenderingCompleteEventArgs e)
		{
			viewer.SetDisplayMode(DisplayMode.PrintLayout);
		}

		void OnPrint()
		{
			var Handler = ReportPrinted;
			if (Handler != null)
				Handler(this, new EventArgs());
		}

		void btnRunReport_Click(object sender, EventArgs e)
		{
			if (Report == null)
				return;

			viewer.Clear();
			Report.Seek(0, 0);
			viewer.LocalReport.LoadReportDefinition(Report);

			BuildDatasources();
			BuildReportParameters();
			viewer.RefreshReport();
		}

		void BuildReportParameters()
		{
			List<ReportParameter> parameters = new List<ReportParameter>();
			ReportParser.ReportParameters.ToList().ForEach(p =>
				{
					if (p.ParameterEntryUserControl is MultipleValidValuesUserControl)
						parameters.Add(new ReportParameter(p.Name, (p.Value as object[]).Cast<string>().ToArray()));
					else
						parameters.Add(new ReportParameter(p.Name, p.Value.ToString()));
				});
			viewer.LocalReport.SetParameters(parameters);
		}
		void BuildDatasources()
		{
			viewer.LocalReport.DataSources.Clear();

			foreach (var dataprovider in ReportParser.DataProviders)
			{
				ReportDataSource rptDatasource = new ReportDataSource(dataprovider.Name);
				viewer.LocalReport.DataSources.Add(rptDatasource);

				SqlCommand cmd = new SqlCommand(dataprovider.CommandText, DatabaseConnection);
				dataprovider.ParameterMappings.ToList().ForEach(kp =>
				{
					RdlReportParameter rptParameter = ReportParser.ReportParameters.Where(rp => rp.Name.ToUpper() == kp.Key.ToUpper()).SingleOrDefault();

					if (rptParameter.ParameterEntryUserControl is MultipleValidValuesUserControl)
					{
						string[] values = (rptParameter.Value as object[]).Select(s => "'" + s.ToString() + "'").ToArray();
						cmd.CommandText = cmd.CommandText.Replace(kp.Value, string.Join(",", values));
					}
					else
					{
						SqlParameter param = new SqlParameter() { ParameterName = kp.Value };
						param.Value = rptParameter.Value;
						param.DbType = rptParameter.GetSqlType;
						cmd.Parameters.Add(param);
					}
				});
				SqlDataAdapter da = new SqlDataAdapter(cmd);
				DataSet ds = new DataSet();

				if (DatabaseConnection.State != ConnectionState.Open)
					DatabaseConnection.Open();

				da.Fill(ds);
				DatabaseConnection.Close();
				rptDatasource.Value = ds.Tables[0];
			}
		}

		/// <summary>
		/// </summary>
		/// <param name="connection"></param>
		/// <exception cref="ArgumentNullException" />
		public void Initialize(IDbConnection connection)
		{
			if (connection == null)
				throw new ArgumentNullException("connection");

			DatabaseConnection = connection as SqlConnection;
		}
		public void LoadDefinition(string stream)
		{
			MemoryStream ms = new MemoryStream();
			byte[] buffer = System.Text.Encoding.ASCII.GetBytes(stream);
			ms.Write(buffer, 0, buffer.Length);
			LoadDefinition(ms);
		}
		public void LoadDefinition(Stream stream)
		{
			try
			{
				Report = null;
				ReportParser = null;

				viewer.Clear();

				Report = stream;
				ReportParser = new RdlParser(stream, DatabaseConnection);

				pnlParameters.Controls.Clear();
				ReportParser.ReportParameters.ToList().ForEach(rp =>
					{
						if (rp.ParameterEntryUserControl is Control)
							pnlParameters.Controls.Add((Control)rp.ParameterEntryUserControl);
					});

				if (ReportParser.ReportParameters.Count == 0)
					btnRunReport_Click(null, null);
			}
			catch (Exception ex)
			{
				log.Error("", ex);
				MessageBox.Show(ex.Message);
			}
		}
	}
}
